package pl.edu.pw.stud.ltrzaska.validator;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
import org.apache.log4j.Logger;

import pl.edu.pw.stud.ltrzaska.logic.PolicyViolation;
import pl.edu.pw.stud.ltrzaska.logic.ValidationContext;
import pl.edu.pw.stud.ltrzaska.policy.entity.Directory;
import pl.edu.pw.stud.ltrzaska.policy.entity.File;
import pl.edu.pw.stud.ltrzaska.policy.entity.FilesystemObject;
import pl.edu.pw.stud.ltrzaska.validator.iface.IFilesystemObjectValidator;

public class SizeValidator implements IFilesystemObjectValidator {
	private final static Logger LOGGER = Logger.getLogger(SizeValidator.class);

	private long getSize(String line) {
		
		Pattern p = Pattern.compile("\\d+");
		Matcher m = p.matcher(line);
		long num = 0;
		while (m.find()) {
			num = Long.parseLong(m.group());
		}
		Pattern p2 = Pattern.compile("[a-zA-Z]+");
		Matcher m2 = p2.matcher(line);
		String unit = "";
		while (m2.find()) {
			unit = m2.group();
		}
		
		unit = unit.toLowerCase().trim();
		if ("kb".equals(unit)) {
			num = num << 10;
		} else if ("mb".equals(unit)) {
			num = num << 20;
		} else if ("gb".equals(unit)) {
			num = num << 30;
		} else if ("tb".equals(unit)) {
			num = num << 40;
		}
		return num;
	}

	// TODO write specific existence validation for Group and Sequence
	@Override
	public boolean validate(FilesystemObject policyFsObj, FileObject virtualFsObj, ValidationContext vc) throws FileSystemException {
		LOGGER.debug("SizeValidator.validate() for FilesystemObject [" + policyFsObj.getRefname() + "]");

		long contSize = this.measureSize(virtualFsObj);
		if (policyFsObj.getMaxSize() != null) {
			if (this.getSize(policyFsObj.getMaxSize()) < contSize) {
				String shortD = "Maksymalny rozmiar obiektu " + policyFsObj.getMaxSize() + ". Rozmiar obiektu (Bajtow): " + String.valueOf(contSize);
				PolicyViolation disc = new PolicyViolation(this.getClass(), "Przekroczony rozmiar", shortD, policyFsObj, virtualFsObj);
				vc.reportDiscrepancy(disc);
				LOGGER.debug("Znaleziono niezgodnosc: Przekroczono maksymalny rozmiar obiektu, max: " + policyFsObj.getMaxSize() + " obiekt " + policyFsObj.getName());
				return false;
			}
		}
		if (policyFsObj.getMinSize() != null) {
			if (this.getSize(policyFsObj.getMinSize()) > contSize) {
				String shortD = "Minimalny rozmiar obiektu " + policyFsObj.getMinSize() + ". Rozmiar obiektu (Bajtow): " + contSize;
				PolicyViolation disc = new PolicyViolation(this.getClass(), "Zbyt maly rozmiar obiektu", shortD, policyFsObj, virtualFsObj);
				vc.reportDiscrepancy(disc);
				LOGGER.debug("Znaleziono niezgodnosc: Zbyt maly rozmiar obiektu, min: " + policyFsObj.getMinSize() + " obiekt " + policyFsObj.getName());
				return false;
			}
		}
		return true;
	}

	private long measureSize(FileObject virtualFsObj) {
		try {
			if(virtualFsObj != null) {
				if(virtualFsObj.getType() == FileType.FILE) {
					return virtualFsObj.getContent().getSize();
				} else if(virtualFsObj.getType() == FileType.FOLDER) {
					long sum = 0;
					FileObject[] filesysChildren = virtualFsObj.getChildren();
					if(filesysChildren.length > 0) {
						for (FileObject fo : filesysChildren) {
							sum += this.measureSize(fo);
						}
					}
					return sum;
				} else return 0;
			}
		} catch (FileSystemException e) {
			LOGGER.error("", e);
		}
		return 0;
	}

	@Override
	public boolean canValidate(FilesystemObject pfo, FileObject vfo) {
		if (pfo instanceof File || pfo instanceof Directory) {
			return true;
		}
		return false;
	}
}
